import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import pandas as pd
import math
import os
import sys
from tkinter import scrolledtext
from config_manager import get_config_manager

class XLSXViewer:
    def __init__(self, root):
        self.root = root
        self.root.title("XLSX 表格查看器")
        
        # 配置管理器
        self.config_manager = get_config_manager()
        
        # 从配置中获取窗口大小和布局设置
        _, _, _, window_width, window_height, self.checkbox_cols_per_row, self.filter_cols_per_row = self.config_manager.get_xlsx_config()
        
        # 设置窗口大小和位置（屏幕居中）
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        self.root.geometry(f"{window_width}x{window_height}+{x}+{y}")
        self.window_width = window_width
        self.window_height = window_height
        
        # 设置窗口图标（简化版本，避免兼容性问题）
        try:
            # 在打包后的EXE中，图标文件位于临时目录
            if hasattr(sys, '_MEIPASS'):
                # PyInstaller打包环境
                icon_path = os.path.join(sys._MEIPASS, 'logo.ico')
            else:
                # 开发环境
                icon_path = os.path.join(os.path.dirname(__file__), "logo.ico")
            
            # 仅尝试设置窗口图标，忽略任务栏图标
            self.root.iconbitmap(icon_path)
        except (tk.TclError, Exception):
            # 如果图标设置失败，静默忽略错误
            pass
        

        
        # 数据相关变量
        self.df = None
        self.current_page = 1
        self.rows_per_page = 20
        self.selected_columns = []
        self.all_columns = []
        self.current_row_index = 0  # 当前选中的行索引
        
        # 导航变量
        self.file_path_var = tk.StringVar()
        self.page_var = tk.StringVar()
        self.page_info_var = tk.StringVar()
        self.row_var = tk.StringVar()  # 用于行号跳转
        
        # 筛选变量
        self.filter_vars = {}  # 存储每个列的筛选条件
        self.filter_frame = None  # 筛选框架
        self.current_filter = {}  # 当前应用的筛选条件
        
        # 创建界面
        self.create_widgets()
        
    def create_widgets(self):
        # 创建Notebook用于切换视图
        self.notebook = ttk.Notebook(self.root)
        self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        # 表格视图框架
        table_frame = ttk.Frame(self.notebook)
        self.notebook.add(table_frame, text="表格视图")
        
        # 在表格视图中创建导航控件
        self.create_table_navigation(table_frame)
        
        # 创建表格容器框架
        table_container = ttk.Frame(table_frame)
        table_container.pack(fill=tk.BOTH, expand=True)
        
        # 创建Treeview来显示数据
        self.tree = ttk.Treeview(table_container)
        self.tree.pack(fill=tk.BOTH, expand=True, side=tk.LEFT)
        
        # 添加垂直滚动条
        v_scrollbar = ttk.Scrollbar(table_container, orient=tk.VERTICAL, command=self.tree.yview)
        v_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.tree.configure(yscrollcommand=v_scrollbar.set)
        
        # 添加水平滚动条（初始隐藏）
        self.h_scrollbar = ttk.Scrollbar(table_frame, orient=tk.HORIZONTAL, command=self.tree.xview)
        self.tree.configure(xscrollcommand=self.on_horizontal_scroll)
        
        # 详情视图框架
        self.detail_frame = ttk.Frame(self.notebook)
        self.notebook.add(self.detail_frame, text="详情视图")
        
        # 在详情视图中创建导航控件
        self.create_detail_navigation(self.detail_frame)
        
        # 详情视图内容
        self.detail_canvas = tk.Canvas(self.detail_frame)
        self.detail_scrollbar = ttk.Scrollbar(self.detail_frame, orient="vertical", command=self.detail_canvas.yview)
        self.detail_scrollable_frame = ttk.Frame(self.detail_canvas)
        
        # 创建一个窗口项目来容纳可滚动框架
        self.detail_canvas_window = self.detail_canvas.create_window((0, 0), window=self.detail_scrollable_frame, anchor="nw")
        
        self.detail_canvas.configure(yscrollcommand=self.detail_scrollbar.set)
        
        self.detail_canvas.pack(side="left", fill="both", expand=True)
        self.detail_scrollbar.pack(side="right", fill="y")
        
        # 绑定配置事件以更新滚动区域
        self.detail_scrollable_frame.bind("<Configure>", self.on_detail_frame_configure)
        self.detail_canvas.bind("<Configure>", self.on_detail_canvas_configure)
        
        # 绑定Treeview选择事件
        self.tree.bind("<<TreeviewSelect>>", self.on_treeview_select)
        
        # 绑定Notebook Tab切换事件
        self.notebook.bind("<<NotebookTabChanged>>", self.on_tab_changed)
        
        # 默认显示第一行数据
        if self.df is not None and len(self.df) > 0:
            self.current_row_index = 0
            row_data = self.df.iloc[self.current_row_index]
            self.update_detail_view(row_data)
            self.update_row_info()
        
    def on_tab_changed(self, event):
        """处理Tab切换事件"""
        # 获取当前选中的Tab
        selected_tab = self.notebook.select()
        tab_text = self.notebook.tab(selected_tab, "text")
        
        # 如果切换到详情视图且没有选中行，则显示第一行数据
        if tab_text == "详情视图" and self.df is not None and len(self.df) > 0:
            # 检查是否已经有选中的行（通过current_row_index是否在有效范围内判断）
            if not (0 <= self.current_row_index < len(self.df)):
                self.current_row_index = 0
                row_data = self.df.iloc[self.current_row_index]
                self.update_detail_view(row_data)
                self.update_row_info()
        
    def create_table_navigation(self, parent):
        """为表格视图创建导航控件"""
        # 文件选择框架
        file_frame = ttk.Frame(parent)
        file_frame.pack(fill=tk.X, padx=10, pady=5)
        
        ttk.Label(file_frame, text="选择文件:").pack(side=tk.LEFT)
        self.file_path_var = tk.StringVar()
        ttk.Entry(file_frame, textvariable=self.file_path_var, width=50).pack(side=tk.LEFT, padx=5)
        ttk.Button(file_frame, text="浏览", command=self.browse_file).pack(side=tk.LEFT, padx=5)
        
        # 列选择框架（带滚动条）
        column_frame = ttk.LabelFrame(parent, text="选择要显示的列")
        column_frame.pack(fill=tk.X, padx=10, pady=5)
        
        # 全选/取消全选按钮
        button_frame = ttk.Frame(column_frame)
        button_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Button(button_frame, text="全选", command=self.select_all_columns).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="取消全选", command=self.deselect_all_columns).pack(side=tk.LEFT, padx=5)
        
        # 创建列选择复选框的滚动容器
        checkbox_container = ttk.Frame(column_frame)
        checkbox_container.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 创建画布和滚动条
        checkbox_canvas = tk.Canvas(checkbox_container, height=120)  # 固定高度
        checkbox_scrollbar = ttk.Scrollbar(checkbox_container, orient="vertical", command=checkbox_canvas.yview)
        
        # 列选择复选框框架（放在画布中）
        self.checkbox_frame = ttk.Frame(checkbox_canvas)
        self.checkbox_frame.bind("<Configure>", lambda e: checkbox_canvas.configure(scrollregion=checkbox_canvas.bbox("all")))
        
        checkbox_canvas.create_window((0, 0), window=self.checkbox_frame, anchor="nw")
        checkbox_canvas.configure(yscrollcommand=checkbox_scrollbar.set)
        
        checkbox_canvas.pack(side="left", fill="both", expand=True)
        checkbox_scrollbar.pack(side="right", fill="y")
        
        self.column_vars = {}
        self.column_checkboxes = {}
        
        # 筛选框架（带滚动条）
        self.filter_frame = ttk.LabelFrame(parent, text="筛选条件")
        self.filter_frame.pack(fill=tk.X, padx=10, pady=5)
        
        # 创建筛选条件的滚动容器
        filter_container = ttk.Frame(self.filter_frame)
        filter_container.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 创建画布和滚动条
        filter_canvas = tk.Canvas(filter_container, height=120)  # 固定高度
        filter_scrollbar = ttk.Scrollbar(filter_container, orient="vertical", command=filter_canvas.yview)
        
        # 筛选内容框架（放在画布中）
        self.filter_content_frame = ttk.Frame(filter_canvas)
        self.filter_content_frame.bind("<Configure>", lambda e: filter_canvas.configure(scrollregion=filter_canvas.bbox("all")))
        
        filter_canvas.create_window((0, 0), window=self.filter_content_frame, anchor="nw")
        filter_canvas.configure(yscrollcommand=filter_scrollbar.set)
        
        filter_canvas.pack(side="left", fill="both", expand=True)
        filter_scrollbar.pack(side="right", fill="y")
        
        # 翻页控制框架
        pagination_frame = ttk.Frame(parent)
        pagination_frame.pack(fill=tk.X, padx=10, pady=5)
        
        ttk.Button(pagination_frame, text="上一页", command=self.prev_page).pack(side=tk.LEFT, padx=5)
        ttk.Button(pagination_frame, text="下一页", command=self.next_page).pack(side=tk.LEFT, padx=5)
        
        ttk.Label(pagination_frame, text="跳转到:").pack(side=tk.LEFT, padx=(20, 5))
        self.page_var = tk.StringVar()
        self.page_entry = ttk.Entry(pagination_frame, textvariable=self.page_var, width=5)
        self.page_entry.pack(side=tk.LEFT, padx=5)
        ttk.Button(pagination_frame, text="跳转", command=self.go_to_page).pack(side=tk.LEFT, padx=5)
        
        # 页面信息
        self.page_info_var = tk.StringVar()
        ttk.Label(pagination_frame, textvariable=self.page_info_var).pack(side=tk.RIGHT, padx=5)
        
    def create_detail_navigation(self, parent):
        """为详情视图创建导航控件"""
        # 行号导航控制框架
        navigation_frame = ttk.Frame(parent)
        navigation_frame.pack(fill=tk.X, padx=10, pady=5)
        
        ttk.Button(navigation_frame, text="上一项", command=self.prev_row).pack(side=tk.LEFT, padx=5)
        ttk.Button(navigation_frame, text="下一项", command=self.next_row).pack(side=tk.LEFT, padx=5)
        
        ttk.Label(navigation_frame, text="跳转到行:").pack(side=tk.LEFT, padx=(20, 5))
        row_entry = ttk.Entry(navigation_frame, textvariable=self.row_var, width=5)
        row_entry.pack(side=tk.LEFT, padx=5)
        ttk.Button(navigation_frame, text="跳转", command=self.go_to_row).pack(side=tk.LEFT, padx=5)
        
        # 行信息
        self.row_info_var = tk.StringVar()
        row_info_label = ttk.Label(navigation_frame, textvariable=self.row_info_var)
        row_info_label.pack(side=tk.RIGHT, padx=5)
        
    def browse_file(self):
        file_path = filedialog.askopenfilename(
            title="选择XLSX文件",
            filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")]
        )
        
        if file_path:
            self.file_path_var.set(file_path)
            self.load_data(file_path)
            # 保存配置
            self.save_config()
    
    def load_data(self, file_path):
        try:
            # 读取xlsx文件
            self.df = pd.read_excel(file_path)
            self.all_columns = list(self.df.columns)
            
            # 检查是否有保存的配置，如果有则使用保存的列选择
            saved_file_path, saved_display_columns, saved_filter_conditions, _, _, _, _ = self.config_manager.get_xlsx_config()
            
            # 根据保存的配置或默认值设置初始选中列
            if saved_file_path == file_path and saved_display_columns:
                self.selected_columns = saved_display_columns
                self.current_filter = saved_filter_conditions
            else:
                self.selected_columns = self.all_columns.copy()
                self.current_filter = {}
            
            # 更新列选择复选框
            # 先清空现有的复选框
            for widget in self.checkbox_frame.winfo_children():
                widget.destroy()
            
            self.column_vars = {}
            self.column_checkboxes = {}
            
            # 创建新的复选框，使用grid布局实现多列排列
            self.create_column_checkboxes()
            
            # 更新筛选输入框
            self.update_filter_entries()
            
            # 重置到第一页
            self.current_page = 1
            self.update_table()
            
        except Exception as e:
            messagebox.showerror("错误", f"加载文件时出错: {str(e)}")
    
    def select_all_columns(self):
        for var in self.column_vars.values():
            var.set(True)
        # 只调用一次on_column_checkbox_change来更新筛选输入框
        if self.all_columns:
            self.on_column_checkbox_change(self.all_columns[0])
        
    def deselect_all_columns(self):
        for var in self.column_vars.values():
            var.set(False)
        # 只调用一次on_column_checkbox_change来更新筛选输入框
        if self.all_columns:
            self.on_column_checkbox_change(self.all_columns[0])
        
    def get_selected_columns(self):
        self.selected_columns = [col for col, var in self.column_vars.items() if var.get()]
        return self.selected_columns
        
    def on_column_checkbox_change(self, column):
        """当列复选框状态改变时调用"""
        # 重新创建筛选输入框，只显示已勾选的列
        if hasattr(self, 'filter_content_frame') and self.filter_content_frame is not None:
            # 清除现有的筛选输入框
            for widget in self.filter_content_frame.winfo_children():
                widget.destroy()
            self.filter_vars.clear()
            
            # 获取当前选中的列
            selected_columns = self.get_selected_columns()
            
            # 只为选中的列创建筛选输入框
            # 使用配置的每行筛选输入框数量
            cols_per_row = self.filter_cols_per_row
            
            for i, column_name in enumerate(selected_columns):
                row = i // cols_per_row
                col_pos = i % cols_per_row
                
                ttk.Label(self.filter_content_frame, text=f"{column_name}:").grid(row=row, column=col_pos*2, padx=5, pady=2, sticky="e")
                filter_var = tk.StringVar()
                # 设置筛选输入框的初始值（如果有保存的筛选条件）
                if column_name in self.current_filter:
                    filter_var.set(self.current_filter[column_name])
                self.filter_vars[column_name] = filter_var
                entry = ttk.Entry(self.filter_content_frame, textvariable=filter_var, width=15)
                entry.grid(row=row, column=col_pos*2+1, padx=5, pady=2, sticky="w")
                
                # 绑定回车键事件
                entry.bind('<Return>', lambda event: self.apply_filter())
            
            # 添加筛选按钮（始终创建，无论是否有选中列）
            filter_button_frame = ttk.Frame(self.filter_content_frame)
            total_rows = (len(selected_columns) - 1) // cols_per_row + 1 if selected_columns else 0
            filter_button_frame.grid(row=total_rows, column=0, columnspan=cols_per_row*2, pady=5)
            ttk.Button(filter_button_frame, text="应用筛选", command=self.apply_filter).pack(side=tk.LEFT, padx=5)
            ttk.Button(filter_button_frame, text="清除筛选", command=self.clear_filter).pack(side=tk.LEFT, padx=5)
            
            # 配置列权重，让筛选输入框均匀分布
            for col in range(cols_per_row*2):
                self.filter_content_frame.columnconfigure(col, weight=1)
        
        self.update_table()
        self.update_detail_view()
        # 保存配置
        self.save_config()
    
    def apply_filter(self):
        """应用筛选条件"""
        # 获取筛选条件
        self.current_filter.clear()
        for column, var in self.filter_vars.items():
            filter_text = var.get().strip()
            if filter_text:
                self.current_filter[column] = filter_text
        
        # 更新表格
        self.update_table()
        
        # 如果在详情视图，也更新详情视图
        self.update_detail_view()
        # 保存配置
        self.save_config()
    
    def clear_filter(self):
        """清除筛选条件"""
        # 清除筛选输入框
        for var in self.filter_vars.values():
            var.set("")
        
        # 清除当前筛选条件
        self.current_filter.clear()
        
        # 更新表格
        self.update_table()
        
        # 如果在详情视图，也更新详情视图
        self.update_detail_view()
        # 保存配置
        self.save_config()
        
    def calculate_column_width(self, column_name, data_series, min_width=80, max_width=300):
        """计算列的最佳显示宽度"""
        # 计算列名宽度
        header_width = len(str(column_name)) * 9 + 30  # 每个字符约9像素，加上边距
        
        # 计算数据内容的最大宽度
        max_content_width = 0
        for value in data_series.head(50):  # 只检查前50行以提高性能
            if pd.notna(value):
                content_width = len(str(value)) * 9 + 30
                max_content_width = max(max_content_width, content_width)
        
        # 取列名和数据内容的最大宽度
        calculated_width = max(header_width, max_content_width)
        
        # 限制在最小和最大宽度之间
        return max(min_width, min(calculated_width, max_width))

    def on_horizontal_scroll(self, *args):
        """处理水平滚动事件"""
        self.h_scrollbar.set(*args)

    def update_horizontal_scrollbar_visibility(self):
        """更新水平滚动条的可见性"""
        try:
            # 获取Treeview的内容宽度
            total_width = 0
            for col in self.tree["columns"]:
                total_width += self.tree.column(col, "width")
            
            # 获取Treeview的可见宽度
            tree_width = self.tree.winfo_width()
            
            # 如果内容宽度大于可见宽度，显示滚动条
            if total_width > tree_width and tree_width > 0:
                # 检查滚动条是否已经显示
                try:
                    self.h_scrollbar.winfo_viewable()
                    # 如果已经显示，不需要重复显示
                except tk.TclError:
                    # 如果未显示，则显示滚动条
                    self.h_scrollbar.pack(side=tk.BOTTOM, fill=tk.X)
                    self.h_scrollbar.lift()  # 确保滚动条在最上层
            else:
                # 如果内容宽度小于等于可见宽度，隐藏滚动条
                try:
                    self.h_scrollbar.pack_forget()
                except tk.TclError:
                    pass
        except Exception as e:
            print(f"更新滚动条可见性时出错: {e}")

    def update_detail_checkboxes(self):
        """更新详细视图中的复选框状态"""
        # 详细视图不再包含列选择控件，此方法留空
        pass
        
    def parse_filter_condition(self, column, filter_text, data_series):
        """解析筛选条件，支持比较运算符
        
        支持的运算符：
        - != : 不等于
        - >  : 大于
        - <  : 小于
        - := : 等于（显式指定）
        - 默认：字符串列使用模糊匹配，数值列使用等于匹配
        """
        # 检查是否包含比较运算符
        if "!=" in filter_text:
            # 不等于
            value = filter_text.split("!=", 1)[1].strip()
            # 对于字符串列，使用字符串比较
            if pd.api.types.is_string_dtype(data_series):
                return f"`{column}` != '{value}'"
            else:
                return f"`{column}` != {self._format_filter_value(value, data_series)}"
        elif ">" in filter_text:
            # 大于
            value = filter_text.split(">", 1)[1].strip()
            return f"`{column}` > {self._format_filter_value(value, data_series)}"
        elif "<" in filter_text:
            # 小于
            value = filter_text.split("<", 1)[1].strip()
            return f"`{column}` < {self._format_filter_value(value, data_series)}"
        elif ":=" in filter_text:
            # 等于（显式指定）
            value = filter_text.split(":=", 1)[1].strip()
            # 对于字符串列，使用字符串比较
            if pd.api.types.is_string_dtype(data_series):
                return f"`{column}` == '{value}'"
            else:
                return f"`{column}` == {self._format_filter_value(value, data_series)}"
        else:
            # 默认行为：字符串列使用模糊匹配，数值列使用等于匹配
            # 对于object类型的列，检查是否包含字符串数据
            if pd.api.types.is_string_dtype(data_series) or data_series.dtype == 'object':
                # 使用str.contains进行模糊匹配，忽略大小写
                # 转义字符串中的单引号，避免SQL注入和语法错误
                escaped_text = filter_text.replace("'", "\\'")
                return f"`{column}`.str.contains('{escaped_text}', case=False, na=False)"
            else:
                # 对于非字符串列，使用等于匹配
                return f"`{column}` == {self._format_filter_value(filter_text, data_series)}"
    
    def _format_filter_value(self, value, data_series):
        """格式化筛选值，根据数据类型添加引号"""
        if pd.api.types.is_string_dtype(data_series):
            # 字符串类型，添加引号
            return f"'{value}'"
        else:
            # 数值类型，直接返回
            try:
                # 尝试转换为数值类型
                float(value)
                return value
            except ValueError:
                # 如果无法转换为数值，作为字符串处理
                return f"'{value}'"
    
    def update_table(self):
        """更新表格显示"""
        # 清空现有数据
        for item in self.tree.get_children():
            self.tree.delete(item)
        
        if self.df is not None:
            # 获取选中的列
            selected_columns = self.get_selected_columns()
            
            # 创建筛选后的数据副本
            filtered_df = self.df.copy()
            
            # 应用筛选条件
            if self.current_filter:
                filter_conditions = []
                for column, filter_text in self.current_filter.items():
                    # 检查列是否存在且筛选文本不为空
                    if column in filtered_df.columns and filter_text:
                        # 解析筛选条件，支持比较运算符
                        condition = self.parse_filter_condition(column, filter_text, filtered_df[column])
                        if condition:
                            filter_conditions.append(condition)
                
                # 如果有筛选条件，应用到数据
                if filter_conditions:
                    try:
                        query_str = " and ".join(filter_conditions)
                        filtered_df = filtered_df.query(query_str)
                    except Exception as e:
                        print(f"筛选条件应用失败: {e}")
            
            if selected_columns:
                # 设置列标题
                self.tree["columns"] = selected_columns
                self.tree["show"] = "headings"  # 只显示列标题
                
                # 计算并设置每列的宽度
                for col in selected_columns:
                    self.tree.heading(col, text=col)
                    # 计算合适的列宽
                    col_width = self.calculate_column_width(col, filtered_df[col])
                    self.tree.column(col, width=col_width)
                
                # 计算分页信息
                total_rows = len(filtered_df)
                total_pages = (total_rows - 1) // self.rows_per_page + 1
                current_page = min(self.current_page, total_pages)
                start_idx = (current_page - 1) * self.rows_per_page
                end_idx = min(start_idx + self.rows_per_page, total_rows)
                
                # 显示当前页数据
                page_df = filtered_df.iloc[start_idx:end_idx]
                for _, row in page_df[selected_columns].iterrows():
                    values = ['' if pd.isna(val) else str(val) for val in row]
                    self.tree.insert("", "end", values=values)
                
                # 更新页面信息
                self.page_info_var.set(f"第 {current_page} 页，共 {total_pages} 页")
                self.page_var.set(str(current_page))
            else:
                # 没有选中的列，清空表格
                self.tree["columns"] = []
                self.tree["show"] = ""  # 不显示任何内容
                
                # 更新页面信息
                self.page_info_var.set("第 0 页，共 0 页")
                self.page_var.set("0")
            
            # 更新水平滚动条可见性
            self.root.after(100, self.update_horizontal_scrollbar_visibility)
        
    def prev_page(self):
        if self.current_page > 1:
            self.current_page -= 1
            self.update_table()
            
    def next_page(self):
        if self.df is not None:
            total_rows = len(self.df)
            total_pages = math.ceil(total_rows / self.rows_per_page)
            if self.current_page < total_pages:
                self.current_page += 1
                self.update_table()
                
    def go_to_page(self):
        try:
            page_num = int(self.page_var.get())
            if self.df is not None:
                total_rows = len(self.df)
                total_pages = math.ceil(total_rows / self.rows_per_page)
                if 1 <= page_num <= total_pages:
                    self.current_page = page_num
                    self.update_table()
                else:
                    messagebox.showwarning("警告", f"请输入1到{total_pages}之间的页码")
        except ValueError:
            messagebox.showwarning("警告", "请输入有效的数字")
            
    def prev_row(self):
        """导航到上一行"""
        if self.df is not None and self.current_row_index > 0:
            self.current_row_index -= 1
            
            # 创建筛选后的数据副本
            filtered_df = self.df.copy()
            
            # 应用筛选条件
            if self.current_filter:
                filter_conditions = []
                for column, filter_text in self.current_filter.items():
                    # 检查列是否存在且筛选文本不为空
                    if column in filtered_df.columns and filter_text:
                        # 解析筛选条件，支持比较运算符
                        condition = self.parse_filter_condition(column, filter_text, filtered_df[column])
                        if condition:
                            filter_conditions.append(condition)
                
                # 如果有筛选条件，应用到数据
                if filter_conditions:
                    try:
                        query_str = " and ".join(filter_conditions)
                        filtered_df = filtered_df.query(query_str)
                    except Exception as e:
                        print(f"筛选条件应用失败: {e}")
            
            if self.current_row_index < len(filtered_df):
                row_data = filtered_df.iloc[self.current_row_index]
                self.update_detail_view(row_data)
                self.update_row_info()
    
    def next_row(self):
        """导航到下一行"""
        if self.df is not None and self.current_row_index < len(self.df) - 1:
            self.current_row_index += 1
            
            # 创建筛选后的数据副本
            filtered_df = self.df.copy()
            
            # 应用筛选条件
            if self.current_filter:
                filter_conditions = []
                for column, filter_text in self.current_filter.items():
                    # 检查列是否存在且筛选文本不为空
                    if column in filtered_df.columns and filter_text:
                        # 解析筛选条件，支持比较运算符
                        condition = self.parse_filter_condition(column, filter_text, filtered_df[column])
                        if condition:
                            filter_conditions.append(condition)
                
                # 如果有筛选条件，应用到数据
                if filter_conditions:
                    try:
                        query_str = " and ".join(filter_conditions)
                        filtered_df = filtered_df.query(query_str)
                    except Exception as e:
                        print(f"筛选条件应用失败: {e}")
            
            if self.current_row_index < len(filtered_df):
                row_data = filtered_df.iloc[self.current_row_index]
                self.update_detail_view(row_data)
                self.update_row_info()
    
    def go_to_row(self):
        """跳转到指定行"""
        try:
            row_num = int(self.row_var.get())
            if self.df is not None:
                # 创建筛选后的数据副本
                filtered_df = self.df.copy()
                
                # 应用筛选条件
                if self.current_filter:
                    filter_conditions = []
                    for column, filter_text in self.current_filter.items():
                        # 检查列是否存在且筛选文本不为空
                        if column in filtered_df.columns and filter_text:
                            # 解析筛选条件，支持比较运算符
                            condition = self.parse_filter_condition(column, filter_text, filtered_df[column])
                            if condition:
                                filter_conditions.append(condition)
                    
                    # 如果有筛选条件，应用到数据
                    if filter_conditions:
                        try:
                            query_str = " and ".join(filter_conditions)
                            filtered_df = filtered_df.query(query_str)
                        except Exception as e:
                            print(f"筛选条件应用失败: {e}")
                
                if 1 <= row_num <= len(filtered_df):
                    self.current_row_index = row_num - 1  # 转换为0基索引
                    if self.current_row_index < len(filtered_df):
                        row_data = filtered_df.iloc[self.current_row_index]
                        self.update_detail_view(row_data)
                        self.update_row_info()
                else:
                    messagebox.showwarning("警告", f"请输入1到{len(filtered_df)}之间的行号")
        except ValueError:
            messagebox.showwarning("警告", "请输入有效的数字")
    
    def update_row_info(self):
        """更新行信息显示"""
        if self.df is not None:
            # 创建筛选后的数据副本
            filtered_df = self.df.copy()
            
            # 应用筛选条件
            if self.current_filter:
                filter_conditions = []
                for column, filter_text in self.current_filter.items():
                    # 检查列是否存在且筛选文本不为空
                    if column in filtered_df.columns and filter_text:
                        # 解析筛选条件，支持比较运算符
                        condition = self.parse_filter_condition(column, filter_text, filtered_df[column])
                        if condition:
                            filter_conditions.append(condition)
                
                # 如果有筛选条件，应用到数据
                if filter_conditions:
                    try:
                        query_str = " and ".join(filter_conditions)
                        filtered_df = filtered_df.query(query_str)
                    except Exception as e:
                        print(f"筛选条件应用失败: {e}")
            
            self.row_info_var.set(f"第 {self.current_row_index + 1} 行，共 {len(filtered_df)} 行")
        else:
            self.row_info_var.set("")
            
    def on_treeview_select(self, event):
        """处理表格行选择事件"""
        selected_items = self.tree.selection()
        if selected_items:
            item = selected_items[0]
            # 获取选中项在treeview中的索引
            item_index = self.tree.index(item)
            
            # 计算分页偏移量
            start_idx = (self.current_page - 1) * self.rows_per_page
            
            # 计算在筛选后数据中的索引
            filtered_index = start_idx + item_index
            
            # 创建筛选后的数据副本
            filtered_df = self.df.copy()
            
            # 应用筛选条件
            if self.current_filter:
                filter_conditions = []
                for column, filter_text in self.current_filter.items():
                    # 检查列是否存在且筛选文本不为空
                    if column in filtered_df.columns and filter_text:
                        # 解析筛选条件，支持比较运算符
                        condition = self.parse_filter_condition(column, filter_text, filtered_df[column])
                        if condition:
                            filter_conditions.append(condition)
                
                # 如果有筛选条件，应用到数据
                if filter_conditions:
                    try:
                        query_str = " and ".join(filter_conditions)
                        filtered_df = filtered_df.query(query_str)
                    except Exception as e:
                        print(f"筛选条件应用失败: {e}")
            
            # 确保索引在有效范围内
            if 0 <= filtered_index < len(filtered_df):
                # 获取选中行的数据
                row_data = filtered_df.iloc[filtered_index]
                
                # 更新当前行索引
                self.current_row_index = filtered_index
                
                # 切换到详情视图
                self.notebook.select(self.detail_frame)
                
                # 更新详情视图
                self.update_detail_view(row_data)
                
                # 更新行信息
                self.update_row_info()
    
    def update_detail_view(self, row_data=None):
        # 更新详情视图
        # 清空现有内容
        for widget in self.detail_scrollable_frame.winfo_children():
            widget.destroy()
        
        # 如果没有传入row_data，则根据当前行索引获取数据
        if row_data is None and self.df is not None:
            # 创建筛选后的数据副本
            filtered_df = self.df.copy()
            
            # 应用筛选条件
            if self.current_filter:
                filter_conditions = []
                for column, filter_text in self.current_filter.items():
                    # 检查列是否存在且筛选文本不为空
                    if column in filtered_df.columns and filter_text:
                        # 解析筛选条件，支持比较运算符
                        condition = self.parse_filter_condition(column, filter_text, filtered_df[column])
                        if condition:
                            filter_conditions.append(condition)
                
                # 如果有筛选条件，应用到数据
                if filter_conditions:
                    try:
                        query_str = " and ".join(filter_conditions)
                        filtered_df = filtered_df.query(query_str)
                    except Exception as e:
                        print(f"筛选条件应用失败: {e}")
            
            # 检查当前行索引是否在筛选后的数据范围内
            if 0 <= self.current_row_index < len(filtered_df):
                row_data = filtered_df.iloc[self.current_row_index]
            else:
                row_data = None
        
        # 添加每列的标签和文本框
        if row_data is not None:
            for col in self.selected_columns:
                if col in row_data:
                    # 列名标签
                    label = ttk.Label(self.detail_scrollable_frame, text=f"{col}:", font=("Arial", 10, "bold"))
                    label.pack(anchor=tk.W, padx=10, pady=(10, 0))
                    
                    # 值文本框
                    text_frame = ttk.Frame(self.detail_scrollable_frame)
                    text_frame.pack(fill=tk.X, padx=10, pady=(0, 10))
                    
                    text_widget = scrolledtext.ScrolledText(text_frame, height=3, wrap=tk.WORD)
                    text_widget.insert(tk.END, '' if pd.isna(row_data[col]) else str(row_data[col]))
                    text_widget.configure(state='disabled')
                    text_widget.pack(fill=tk.X, expand=True)
            
            # 如果没有选中的列，显示提示信息
            if not self.selected_columns:
                label = ttk.Label(self.detail_scrollable_frame, text="没有选中的列", font=("Arial", 10, "bold"))
                label.pack(anchor=tk.CENTER, padx=10, pady=10)
            
            # 如果有选中的列但没有数据显示，显示提示信息
            if self.selected_columns and not any(col in row_data for col in self.selected_columns):
                label = ttk.Label(self.detail_scrollable_frame, text="没有数据可显示", font=("Arial", 10, "bold"))
                label.pack(anchor=tk.CENTER, padx=10, pady=10)
        else:
            # 没有数据可显示
            label = ttk.Label(self.detail_scrollable_frame, text="没有数据可显示", font=("Arial", 10, "bold"))
            label.pack(anchor=tk.CENTER, padx=10, pady=10)
        
        # 更新滚动区域
        self.detail_canvas.update_idletasks()
        self.detail_canvas.configure(scrollregion=self.detail_canvas.bbox("all"))

    def create_column_checkboxes(self):
        """创建列选择复选框并根据窗口宽度动态排列"""
        # 销毁现有的复选框
        for widget in self.checkbox_frame.winfo_children():
            widget.destroy()
        
        self.column_vars = {}
        self.column_checkboxes = {}
        
        # 清除现有的筛选输入框
        if hasattr(self, 'filter_content_frame') and self.filter_content_frame is not None:
            for widget in self.filter_content_frame.winfo_children():
                widget.destroy()
            self.filter_vars.clear()
        
        # 创建新的复选框
        for col in self.all_columns:
            # 根据配置设置初始选中状态
            is_checked = col in self.selected_columns if hasattr(self, 'selected_columns') and self.selected_columns else True
            var = tk.BooleanVar(value=is_checked)
            checkbox = ttk.Checkbutton(self.checkbox_frame, text=col, variable=var, 
                                     command=lambda c=col: self.on_column_checkbox_change(c))
            self.column_vars[col] = var
            self.column_checkboxes[col] = checkbox
        
        # 初始排列复选框
        self.update_checkbox_layout()
        
        # 初始化筛选输入框
        if self.all_columns:
            self.on_column_checkbox_change(self.all_columns[0])
        
        # 绑定窗口大小改变事件
        self.root.bind('<Configure>', self.on_window_resize)
    
    def update_checkbox_layout(self):
        """根据窗口宽度更新复选框布局"""
        # 获取框架宽度
        frame_width = self.checkbox_frame.winfo_width()
        
        # 如果宽度为1，说明窗口还未完全渲染，使用默认宽度
        if frame_width <= 1:
            frame_width = 800  # 默认宽度
        
        # 计算每行可显示的复选框数量
        # 使用更精确的方法计算复选框宽度
        checkbox_width = 180  # 增加默认宽度以容纳更长的列名
        
        # 如果有复选框，尝试计算实际宽度
        if self.column_checkboxes:
            # 取第一个复选框来估算宽度
            sample_checkbox = next(iter(self.column_checkboxes.values()))
            # 更新复选框以获取实际宽度
            sample_checkbox.update_idletasks()
            # 获取实际宽度并加上一些边距
            actual_width = sample_checkbox.winfo_reqwidth()
            if actual_width > 0:
                checkbox_width = actual_width + 20  # 增加边距
        
        # 使用配置的每行复选框数量
        cols_per_row = self.checkbox_cols_per_row
        
        # 重新排列复选框 - 使用grid布局实现多列显示
        for i, col in enumerate(self.all_columns):
            checkbox = self.column_checkboxes[col]
            row = i // cols_per_row
            col_pos = i % cols_per_row
            checkbox.grid(row=row, column=col_pos, sticky=tk.W, padx=5, pady=2)
            
        # 配置列权重，让复选框均匀分布
        for col in range(cols_per_row):
            self.checkbox_frame.columnconfigure(col, weight=1)
    
    def on_window_resize(self, event):
        """窗口大小改变事件处理"""
        # 只有当事件源是主窗口时才更新布局
        if event.widget == self.root:
            self.update_checkbox_layout()

    def on_detail_frame_configure(self, event):
        """当详细视图框架大小改变时更新滚动区域"""
        self.detail_canvas.configure(scrollregion=self.detail_canvas.bbox("all"))
    
    def on_detail_canvas_configure(self, event):
        """当详细视图画布大小改变时调整框架宽度"""
        canvas_width = event.width
        self.detail_canvas.itemconfig(self.detail_canvas_window, width=canvas_width)
        self.detail_canvas.configure(scrollregion=self.detail_canvas.bbox("all"))

    def update_filter_entries(self):
        """更新筛选输入框的值"""
        for column, filter_text in self.current_filter.items():
            if column in self.filter_vars:
                self.filter_vars[column].set(filter_text)
    
    def save_config(self):
        """保存当前配置"""
        if self.df is not None and self.file_path_var.get():
            file_path = self.file_path_var.get()
        display_columns = self.get_selected_columns()
        filter_conditions = self.current_filter
        # 保存窗口大小和布局配置
        self.config_manager.set_xlsx_config(file_path, display_columns, filter_conditions,
                                          self.window_width, self.window_height,
                                          self.checkbox_cols_per_row, self.filter_cols_per_row)

if __name__ == "__main__":
    root = tk.Tk()
    app = XLSXViewer(root)
    
    # 程序启动时检查是否有保存的配置
    config_manager = get_config_manager()
    if config_manager.config_exists():
        file_path, display_columns, filter_conditions, _, _, _, _ = config_manager.get_xlsx_config()
        if file_path and os.path.exists(file_path):
            app.file_path_var.set(file_path)
            app.load_data(file_path)
    
    root.mainloop()